余烬缀记

JavaScript 的定时器封装

实现对定时器封装暂停恢复功能

const timeMap = Symbol('timeMap');

class Timer {
        constructor() {
            this[timeMap] = new Map();
        }

        /***
         * 设置延时器,返回延时器ID
         * @param callback
         * @param ms
         * @returns {number}
         */
        setTimeout(callback, ms) {
            let start_time = Date.now();
            let need_time = ms;
            let time_id = setTimeout(() => {
                this.clear(time_id);
                callback();
            }, ms);
            this[timeMap].set(time_id, {
                start_time,
                need_time,
                is_run: true,
                callback,
                type: 'Timeout',
                time_id: time_id
            });
            return time_id;
        }

        /***
         * 设置定时器,返回定时器ID
         * @param callback
         * @param ms
         * @returns {number}
         */
        setInterval(callback, ms) {
            let start_time = Date.now();
            let need_time = ms;
            let time_id = setInterval(() => {
                callback();
            }, ms);
            this[timeMap].set(time_id, {
                start_time,
                need_time,
                is_run: true,
                callback,
                type: 'Interval',
                time_id: time_id
            });
            return time_id;
        }

        /***
         * 停止定时器或延时器
         * @param time_id
         * @returns {boolean}
         */
        stop(time_id) {
            let time = this[timeMap].get(time_id);
            if (time && time.is_run) {
                let now_time = Date.now();
                let type = time.type;
                window[`clear${time.type}`](time.time_id);
                if (type === 'Timeout') {
                    let need_time = time.need_time - (now_time - time.start_time);
                    if (need_time < 0) return;
                    time.need_time = need_time;
                }
                time.start_time = now_time;
                time.is_run = false;
                return true
            }
        }

        /***
         * 停止所有定时器和延时器
         * @returns {boolean}
         */
        stopAll() {
            for (let key of this[timeMap].keys()) {
                this.stop(key);
            }
            return true;
        }
        /***
         * 恢复所有定时器和延时器
         * @returns {boolean}
         */
        restoreAll() {
            for (let key of this[timeMap].keys()) {
                this.restore(key);
            }
            return true;
        }

        /***
         * 恢复定时器或延时器
         * @param time_id
         * @returns {boolean}
         */
        restore(time_id) {
            let time = this[timeMap].get(time_id);
            if (time && !time.is_run) {
                time.time_id = window[`set${time.type}`](() => {
                    time.callback();
                    time.type === 'Timeout' && this.clear(time_id);
                }, time.need_time);
                time.is_run = true;
                return true;
            }
        }

        /***
         * 清除延时器或定时器
         * @param time_id
         * @returns {boolean}
         */
        clear(time_id) {
            let time = this[timeMap].get(time_id);
            if (time) {
                window[`clear${time.type}`](time.time_id);
                this[timeMap].delete(time_id);
                return true;
            }
        }

        /***
         * 清除全部定时器和延时器
         * @returns {boolean}
         */
        clearAll() {
            for (let time of this[timeMap].values()) {
                window[`clear${time.type}`](time.time_id);
            }
            this[timeMap].clear();
            return true;
        }
    }